home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / amiga / hdf / hdf.lha / DFCOMP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1980-02-06  |  17.1 KB  |  522 lines

  1. /***************************************************************************
  2. *
  3. *
  4. *                         NCSA HDF version 3.2r2
  5. *                            October 30, 1992
  6. *
  7. * NCSA HDF Version 3.2 source code and documentation are in the public
  8. * domain.  Specifically, we give to the public domain all rights for future
  9. * licensing of the source code, all resale rights, and all publishing rights.
  10. *
  11. * We ask, but do not require, that the following message be included in all
  12. * derived works:
  13. *
  14. * Portions developed at the National Center for Supercomputing Applications at
  15. * the University of Illinois at Urbana-Champaign, in collaboration with the
  16. * Information Technology Institute of Singapore.
  17. *
  18. * THE UNIVERSITY OF ILLINOIS GIVES NO WARRANTY, EXPRESSED OR IMPLIED, FOR THE
  19. * SOFTWARE AND/OR DOCUMENTATION PROVIDED, INCLUDING, WITHOUT LIMITATION,
  20. * WARRANTY OF MERCHANTABILITY AND WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE
  21. *
  22. ****************************************************************************
  23. */
  24.  
  25. #ifdef RCSID
  26. static char RcsId[] = "@(#)$Revision: 1.3 $";
  27. #endif
  28. /*
  29. $Header: /hdf/hdf/v3.2r2/src/RCS/dfcomp.c,v 1.3 1992/10/23 00:14:11 koziol beta koziol $
  30.  
  31. $Log: dfcomp.c,v $
  32.  * Revision 1.3  1992/10/23  00:14:11  koziol
  33.  * Changed all DFIstr*() and DFImem*() calls to HDstr*() and HDmem*() calls
  34.  * #ifdef'd out the macros Jason defined for Hopen, Hclose, etc. for Vsets
  35.  * Replaced Vset VFREESPACE and VGETSPACE calls with actual calls to HDfreespace
  36.  * and HDgetspace
  37.  * Added a MS-Windows lower lower for file I/O (which may not be completely working
  38.  *
  39.  * Revision 1.2  1992/10/12  18:11:51  koziol
  40.  * Updated for v3.2r2 release
  41.  *
  42.  * Revision 1.1  1992/08/25  21:40:44  koziol
  43.  * Initial revision
  44.  *
  45. */
  46. /*-----------------------------------------------------------------------------
  47.  * File:    dfcomp.c
  48.  * Purpose: File compression
  49.  * Invokes: df.c dfimcomp.c df.h
  50.  * Contents:
  51.  *  DFputcomp: compress image and write it to HDF file
  52.  *  DFgetcomp: read compressed image from HDF file and decompress it
  53.  *  DFCrle: compress string using run length encoding
  54.  *  DFCunrle: decompress string using run length encoding
  55.  * Remarks: DFgetcomp and DFputcomp constitute a general compression interface
  56.  *---------------------------------------------------------------------------*/
  57.  
  58. #include "hdf.h"
  59. #include "herr.h"
  60.  
  61. #define R8_MAX_BLOCKS 32
  62. #define R8_MAX_LENGTH 512
  63.  
  64. /*-----------------------------------------------------------------------------
  65.  * Name:    DFputcomp
  66.  * Purpose: Compress and write images to HDF file
  67.  * Inputs:  file_id: pointer to HDF file
  68.  *          tag, ref: tag, ref of compressed image for writing out
  69.  *          image: image to be compressed
  70.  *          xdim, ydim: dimensions of image
  71.  *          palette: palette associated with image
  72.  *          newpal: modified palette, produced if compression scheme is IMCOMP
  73.  *          scheme: compression scheme to be used
  74.  * Returns: 0 on success, -1 on failure with DFerror set
  75.  * Users:   HDF programmers, DF8putrig, other routines
  76.  * Invokes: DFCrle, DFCimcomp, DFaccess, DFwrite, DFIcheck
  77.  * Remarks: IMCOMP modifies the palette associated with the image
  78.  *          Hence the palette and newpal arguments
  79.  *          This is a general compression interface - to be used anytime image
  80.  *          compression is needed in HDF
  81.  *          Note that rseq does its own compression, because that is part of
  82.  *          the interactive color raster protocol
  83.  *          The space needed for compression and decompression can be allocated
  84.  *          statically or dynamically, depending on the DF_DYNAMIC flag, and
  85.  *          for entire image or part of it (reused) depending on availability
  86.  *          Accordingly, writing out is whole image, or row by row
  87.  *          Note that compression is always row by row for RLE.
  88.  *---------------------------------------------------------------------------*/
  89.  
  90. #ifdef PROTOTYPE
  91. int DFputcomp(int32 file_id, uint16 tag, uint16 ref, uint8 *image, int32 xdim,
  92.              int32 ydim, uint8 *palette, uint8 *newpal, int16 scheme)
  93. #else
  94. int DFputcomp(file_id, tag, ref, image, xdim, ydim, palette, newpal, scheme)
  95.     int32 file_id;
  96.     uint16 tag, ref;
  97.     uint8 *image;
  98.     int32 xdim, ydim;
  99.     uint8 *palette;
  100.     uint8 *newpal;
  101.     int16 scheme;
  102. #endif
  103. {
  104.     char *FUNC="DFputcomp";
  105.     uint8 *buffer;             /* buffer to hold compressed image */
  106.     uint8 *in;                 /* pointer to input for compression */
  107.     uint8 *out;                /* pointer to space for compressed output */
  108.     int32 cisize;              /* maximum size of compressed image */
  109.     int32 crowsize;            /* maximum size of compressed row */
  110.     intn  buftype;             /* buftype = 1: buffer enough for whole image*/
  111.                                /* buftype = 2: buffer holds 1 row */
  112.     int32 n;                   /* number of compressed bytes produced */
  113.     int32 total;               /* total compressed bytes produced so far */
  114.     int32 i;
  115.     int ret=0;
  116.     int32 aid;
  117.  
  118.     if (!HDvalidfid(file_id) || !tag || !ref
  119.        || xdim <= 0 || ydim <= 0 || !image) {
  120.        HERROR(DFE_ARGS);
  121.        return FAIL;
  122.     }
  123.  
  124.     switch (scheme) {
  125.       case DFTAG_RLE:
  126.        cisize = ydim*(xdim*121/120+1); /* 120 chars can compress to 121! */
  127.        crowsize = xdim*121/120 + 128;
  128.  
  129.        /* allocate buffer for compression */
  130.        buffer = HDgetspace((uint32)cisize);
  131.        if (!buffer) {
  132.            buffer = HDgetspace((uint32)crowsize);
  133.            if (!buffer) {
  134.                HERROR(DFE_NOSPACE);
  135.                return FAIL;
  136.            }
  137.            buftype = 2;        /* compress and write out row by row */
  138.        }
  139.        else buftype = 1;       /* can hold whole image, then write */
  140.  
  141.        in = image;
  142.        out = buffer;
  143.        n = total = 0;          /* no bytes compressed so far */
  144.  
  145.        if (buftype == 2) {
  146.            int32 num_blocks;
  147.            int32 block_length;
  148.  
  149.            num_blocks = (ydim > (int32)R8_MAX_BLOCKS) ? (int32)R8_MAX_BLOCKS
  150.                         : ydim;
  151.            block_length = (xdim > (int32)R8_MAX_LENGTH) ? (int32)R8_MAX_LENGTH
  152.                         : xdim;
  153.            aid = HLcreate(file_id, tag, ref, block_length, num_blocks);
  154.            if (aid == FAIL) {
  155.                return FAIL;
  156.            }
  157.        }
  158.  
  159.        /* compress row by row */
  160.        for (i=0; i<ydim; i++) {
  161.            n = DFCrle((VOIDP)in, (VOIDP)out, xdim); /* compress row */
  162.            in += xdim;                /* move input pointer */
  163.            total += n;                /* keep running total */
  164.            if (buftype==1)       /* can hold whole image */
  165.                out = &buffer[total]; /* move out buffer pointer */
  166.            else {                /* buffer too small, */
  167.                                       /* write out what was produced */
  168.                if (Hwrite(aid, n, buffer) == FAIL) {
  169.                    ret = -1;       /* flag value */
  170.                    break;
  171.                }
  172.                out = buffer;   /* reset output pointer */
  173.            }
  174.        }
  175.  
  176.        if (buftype==1) { /* write out entire image */
  177.            ret = Hputelement(file_id, tag, ref, buffer, total);
  178.            HDfreespace(buffer);
  179.        }
  180.        break;
  181.  
  182.       case DFTAG_IMC:
  183.         if (!palette || !newpal) { /* need palette and newpal */
  184.            HERROR(DFE_ARGS);
  185.             return FAIL;
  186.         }
  187.         cisize = xdim*ydim/4;  /* IMCOMP always cuts to 1/4 */
  188.  
  189.         buffer = HDgetspace((uint32)cisize);
  190.         if (!buffer) {
  191.             HERROR(DFE_NOSPACE);
  192.             return FAIL;
  193.         }
  194.  
  195.         DFCimcomp(xdim, ydim, image, buffer, palette, newpal, 0);
  196.         ret = Hputelement(file_id, tag, ref, buffer, cisize);
  197.  
  198.        HDfreespace(buffer);
  199.  
  200.         break;
  201.  
  202.     default:                   /* unknown compression scheme */
  203.         HERROR(DFE_ARGS);
  204.         return FAIL;
  205.     }
  206.  
  207.     return(ret);
  208. }
  209.  
  210. /*-----------------------------------------------------------------------------
  211.  * Name:    DFgetcomp
  212.  * Purpose: Read compressed image and decompress it
  213.  * Inputs:  file_id: HDF file pointer
  214.  *          tag, ref: id of image to be decompressed
  215.  *          image: space to return decompressed image in
  216.  *          xdim, ydim: dimensions of decompressed image
  217.  *          scheme: compression scheme used
  218.  * Returns: 0 on success, -1 on failure with DFerror set
  219.  * Users:   HDF programmers, DF8getrig, other routines
  220.  * Invokes: DFIcheck, DFIfind, DFaccess, DFread, DFCunrle, DFCunimcomp
  221.  * Remarks: Will use dynamic/static memory allocation for buffer
  222.  *          will read in image in parts if memory insufficient
  223.  *          Decompression of rle is not necessarily row by row
  224.  *          Other encodings can also be decoded with this
  225.  *---------------------------------------------------------------------------*/
  226.  
  227. #ifdef PROTOTYPE
  228. int DFgetcomp(int32 file_id, uint16 tag, uint16 ref, uint8 *image, int32 xdim,
  229.              int32 ydim, uint16 scheme)
  230. #else
  231. int DFgetcomp(file_id, tag, ref, image, xdim, ydim, scheme)
  232.     int32 file_id;
  233.     uint16 tag, ref;
  234.     uint8 *image;
  235.     int32 xdim, ydim;
  236.     uint16 scheme;
  237. #endif
  238. {
  239.     char *FUNC="DFgetcomp";
  240.     uint8 *buffer;
  241.     uint8 *in;
  242.     uint8 *out;
  243.     int32 cisize, crowsize, buflen, bufleft; /* bufleft: bytes left in buffer*/
  244.  
  245.     int32 i;
  246.     int32 totalread;
  247.     int32 n;
  248.     int32 aid;
  249.  
  250.     if (!HDvalidfid(file_id) || !tag || !ref
  251.         || xdim <= 0 || ydim <= 0 || !image) {
  252.        HERROR(DFE_ARGS);
  253.        return FAIL;
  254.     }
  255.  
  256.     aid = Hstartread(file_id, tag, ref);
  257.     if (aid == FAIL) {
  258.         HERROR(DFE_NOMATCH);
  259.         return FAIL;
  260.     }
  261.     if (Hinquire(aid, (int32*)NULL, (uint16*)NULL, (uint16*)NULL, &cisize,
  262.                 (int32*)NULL, (int32*)NULL, (int16*)NULL, (int16*)NULL) == FAIL) {
  263.        return FAIL;
  264.     }
  265.  
  266.     switch (scheme) {
  267.       case DFTAG_RLE:
  268.        crowsize = xdim*121/120 + 128; /* max size of a row */
  269.  
  270.        buffer = HDgetspace((uint32)cisize);
  271.        if (!buffer) {
  272.            buffer = HDgetspace((uint32)crowsize);
  273.            if (!buffer) {
  274.                HERROR(DFE_NOSPACE);
  275.                Hendaccess(aid);
  276.                return FAIL;
  277.            }
  278.            buflen = crowsize;
  279.        }
  280.        else buflen = cisize;
  281.  
  282.        in = buffer;
  283.        out = image;
  284.        if ((n=Hread(aid, buflen, in))<0) {
  285.            HDfreespace(buffer);
  286.            Hendaccess(aid);
  287.            return(-1);
  288.        }
  289.        totalread = n;
  290.        bufleft = n;
  291.        for (i=0; i<ydim; i++) {
  292.            n = DFCunrle(in, out, xdim, !i); /* no of bytes used up */
  293.            /* last arg=TRUE if i=0 - resets decompress */
  294.            in += n;
  295.            out += xdim;
  296.            bufleft -= n;
  297.            /* check if more bytes may be needed for next read */
  298.            if ((bufleft<crowsize) && (totalread<cisize)) {
  299.                HDmemcpy(buffer, in, (size_t)bufleft);
  300.                in = buffer;
  301.                if ((n=Hread(aid,buflen-bufleft,(uint8 *)&in[bufleft]))<0) {
  302.                    HDfreespace(buffer);
  303.                    Hendaccess(aid);
  304.                    return FAIL;
  305.                }
  306.                totalread += n;
  307.                bufleft += n;
  308.            }
  309.        }
  310.  
  311.        Hendaccess(aid);
  312.        HDfreespace(buffer);
  313.  
  314.        break;
  315.  
  316.       case DFTAG_IMC:
  317.        crowsize = xdim;        /* size of compressed row */
  318.  
  319.        buffer = HDgetspace((uint32)cisize);
  320.        if (!buffer) {
  321.            buffer = HDgetspace((uint32)crowsize);
  322.            if (!buffer) {
  323.                HERROR(DFE_NOSPACE);
  324.                Hendaccess(aid);
  325.                return FAIL;
  326.            }
  327.            buflen = crowsize;
  328.        }
  329.        else buflen = cisize;
  330.        if (buflen>=cisize) {
  331.            if (Hread(aid, cisize, buffer) < cisize) {
  332.                HDfreespace(buffer);
  333.                Hendaccess(aid);
  334.                return FAIL;
  335.            }
  336.            /* HDfreespace(buffer); */
  337.            Hendaccess(aid);
  338.            DFCunimcomp(xdim, ydim, buffer, image);
  339.            HDfreespace(buffer);
  340.            break;              /* go to end of switch */
  341.        }
  342.  
  343.        in = buffer;            /* if can only read piecemeal */
  344.        out = image;
  345.        if ((n=Hread(aid, buflen, in))<0) {
  346.            HDfreespace(buffer);
  347.            Hendaccess(aid);
  348.            return FAIL;
  349.        }
  350.        totalread = n;
  351.        bufleft = n;
  352.        for (i=0; i<ydim; i+=4) {
  353.            DFCunimcomp(xdim, (int32)4, in, out);
  354.            in += xdim;
  355.            out += 4*xdim;
  356.            bufleft -= xdim;
  357.            if ((bufleft<crowsize) && (totalread<cisize)) {
  358.                HDmemcpy(buffer, in, (size_t)bufleft);
  359.                in = buffer;
  360.                if ((n=Hread(aid,buflen-bufleft,(uint8 *)&in[bufleft]))<0) {
  361.                    HDfreespace(buffer);
  362.                    Hendaccess(aid);
  363.                    return FAIL;
  364.                }
  365.                totalread += n;
  366.                bufleft += n;
  367.            }
  368.        }
  369.  
  370.        HDfreespace(buffer);
  371.        Hendaccess(aid);
  372.  
  373.        break;
  374.  
  375.       default:                 /* unknown scheme */
  376.        HERROR(DFE_ARGS);
  377.        return FAIL;
  378.     }
  379.  
  380.     return SUCCEED;
  381. }
  382.  
  383. /*-----------------------------------------------------------------------------
  384.  * Name:    DFCrle
  385.  * Purpose: compress a string of bytes
  386.  * Inputs:  buf: buffer containing data to be compressed
  387.  *          bufto: space for compressed data - assumed big enough
  388.  *          len: number of bytes to compress
  389.  * Returns: number of compressed bytes on success, -1 on failure
  390.  * Users:   HDF programmers, DFputcomp, other routines
  391.  * Invokes: none
  392.  * Remarks: Written for efficiency
  393.  *---------------------------------------------------------------------------*/
  394.  
  395. #ifdef PROTOTYPE
  396. int32 DFCrle(VOIDP buf, VOIDP bufto, int32 len)
  397. #else
  398. int32 DFCrle(buf,bufto,len)
  399.     VOIDP buf;
  400.     VOIDP bufto;
  401.     int32 len;
  402. #endif
  403. {
  404.     register uint8 * p;
  405.     register uint8 * q;
  406.     register uint8 * cfoll;
  407.     register uint8 * clead;
  408.     uint8 * begp;
  409.     int32 i;
  410.  
  411.     p = (uint8 *)buf;
  412.     cfoll = (uint8 *)bufto;             /* place to copy to */
  413.     clead = cfoll + 1;
  414.  
  415.     begp = p;
  416.     while (len > 0) {           /* encode stuff until gone */
  417.  
  418.         q = p + 1;
  419.         i = len-1;
  420.         while (i && i+120 > len && *p == *q) {
  421.             q++;
  422.             i--;
  423.         }
  424.  
  425.         if (q - p > 2) {        /* three in a row */
  426.             if (p > begp) {
  427.                 *cfoll = (uint8)(p - begp);
  428.                 cfoll = clead;
  429.             }
  430.             *cfoll++ = (uint8)128 | (uint8)(q-p); /* len of seq */
  431.             *cfoll++ = *p;      /* char of seq */
  432.             len -= q-p;         /* subtract len of seq */
  433.             p = q;
  434.             clead = cfoll+1;
  435.             begp = p;
  436.         }
  437.         else {
  438.             *clead++ = *p++;    /* copy one char */
  439.             len--;
  440.             if (p - begp > 120) {
  441.                 *cfoll = (uint8)(p - begp);
  442.                 cfoll = clead++;
  443.                 begp = p;
  444.             }
  445.         }
  446.  
  447.     }
  448. /*
  449.  *  fill in last bytecount
  450.  */
  451.     if (p > begp)
  452.         *cfoll = (uint8)(p - begp);
  453.     else
  454.         clead--;                    /* don't need count position */
  455.  
  456.     return((int32)((uint8*)clead - (uint8*)bufto)); /* how many encoded */
  457. }
  458.  
  459. /*-----------------------------------------------------------------------------
  460.  * Name:    DFCunrle
  461.  * Purpose: decompress run length encoding
  462.  * Inputs:  buf: buffer containing compressed data
  463.  *          bufto: space for returning decompressed data
  464.  *          outlen: number of *decompressed* bytes desired.
  465.  *          resetsave: don't use any stored state info - used for fresh image
  466.  * Returns: number of compressed bytes used up on success, -1 on failure
  467.  * Users:   HDF programmers, DFgetcomp, other routines
  468.  * Invokes: none
  469.  * Remarks: has been modified so it will decompress even non-rowwise compression
  470.  *          Hence the static storage stuff
  471.  *---------------------------------------------------------------------------*/
  472.  
  473. #ifdef PROTOTYPE
  474. int32 DFCunrle(uint8 *buf, uint8 *bufto, int32 outlen, int resetsave)
  475. #else
  476. int32 DFCunrle(buf,bufto,outlen, resetsave)
  477.     uint8 *buf;
  478.     uint8 *bufto;
  479.     int32 outlen;
  480.     int resetsave;
  481. #endif
  482. {
  483.     register int cnt;
  484.     register uint8 * p;
  485.     register uint8 * q;
  486.     uint8 * endp;
  487.     static uint8 save[255], *savestart=NULL, *saveend=NULL;
  488.     /* save has a list of decompressed bytes not returned in
  489.        previous call.  savestart and saveend specify the position
  490.        at which this list starts and ends in the array save */
  491.  
  492.     p = (uint8 *)buf;
  493.     endp = (uint8 *)bufto + outlen;
  494.     q = (uint8 *)bufto;
  495.     if (resetsave) savestart = saveend = save; /* forget saved state */
  496.     while ((saveend>savestart) && (q<endp)) /* copy saved stuff */
  497.         *q++ = *savestart++;
  498.     if (savestart>=saveend) savestart = saveend = save;        /* all copied */
  499.     while (q < endp) {
  500.         cnt = *p++;            /* count field */
  501.         if (!(cnt & 128)) {    /* is set of uniques */
  502.             while (cnt--) {
  503.                 if (q<endp)
  504.                     *q++ = *p++; /* copy unmodified */
  505.                 else
  506.                     *saveend++ = *p++;
  507.             }
  508.         }
  509.         else {
  510.             cnt &= 127;                /* strip high bit */
  511.             while (cnt--) {
  512.                 if (q<endp)
  513.                     *q++ = *p;  /* copy unmodified */
  514.                 else
  515.                     *saveend++ = *p;
  516.             }
  517.             p++;                /* skip that character */
  518.         }
  519.     }
  520.     return((int32)(p - buf));
  521. }
  522.